package cn.xorange.commons.core.basic.service;

import cn.hutool.core.util.ReflectUtil;
import cn.xorange.commons.data.build.KeyBuild;
import cn.xorange.commons.data.constants.FieldConstants;
import cn.xorange.commons.data.core.entity.BaseEntity;
import cn.xorange.commons.data.core.mapper.MBaseMapper;
import cn.xorange.commons.data.utils.DataUtil;
import cn.xorange.commons.data.utils.ParamUtil;
import cn.xorange.commons.exception.DataException;
import cn.xorange.commons.core.constants.SysConstants;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.*;

/**
 * @author : yangjian
 * date : 2024/1/16
 * description :
 */
public class BaseService <T extends BaseEntity, M extends MBaseMapper<T>>  {

    protected Log log = LogFactory.getLog(getClass());
    public BaseService(){
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
        Class<T> t = (Class<T>) pt.getActualTypeArguments()[0];
        this.entity = ReflectUtil.newInstance(t.getName());
    }

    public BaseService(T t){
        this.entity = t;
    }


    @Autowired
    protected M mapper;
    @Resource
    BaseBatchService batchService;

    private final T entity;

    public void setNewId(T t){
        KeyBuild.setNewId(t);
    }

    public T getById(Long id){
        return mapper.selectById(id,this.entity.getClass());
    }

    public T getEntity(T t) {
        return mapper.select(t);
    }

    public List<T> getList(T t){
        return mapper.selectList(t);
    }

    public int count(T t){
        return mapper.count(t);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public int add(T t){
        return mapper.insert(t);
    }
    @Transactional(rollbackFor = RuntimeException.class)
    public int addBath(List<T> list){
        return DataUtil.bathAddRelationEntity(list,mapper);
    }

    public int addBath(String tableName, List<Map<String,Object>> mapList){
      return this.batchService.insertBathMap(tableName,mapList);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public int delete(T t){
        return mapper.del(t);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public int deleteById(Long id){
        return mapper.delById(id, entity.getClass());
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public int deleteByIds(Long[] ids){
        T t = ReflectUtil.newInstance(this.entity.getClass().getName());
        Field keyField = ParamUtil.getKeyField(this.entity.getClass());
        t.where.in(keyField.getName(),ids);
        return mapper.del(t);
    }


    public void truncate(){
        mapper.truncate(entity);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public int update(T t){
        return mapper.update(t); }

    @Transactional(rollbackFor = RuntimeException.class)
    public void changeStatus(T t) {
        Field keyField = ParamUtil.getKeyField(t.getClass());
        if(Objects.isNull(keyField)){
            throw DataException.entityKeyColNotFound();
        }else {
            Object id = ParamUtil.getKeyValue(t);
            if(Objects.isNull(id)){
                throw DataException.dataKeyValueNull();
            }else {
                if (!ReflectUtil.hasField(t.getClass(), FieldConstants.STATUS)){
                    throw DataException.entityFieldNameError("没有status属性");
                }


                Object status = ReflectUtil.getFieldValue(t,FieldConstants.STATUS);
                if(Objects.isNull(status)){
                    throw DataException.dataValueNull("状态值为空");
                }else {
                    T clazz = (T)ReflectUtil.newInstance(t.getClass());
                    ReflectUtil.setFieldValue(clazz,keyField,id);
                    if(SysConstants.FLAG_SUCCESS.equals(status)){
                        ReflectUtil.setFieldValue(clazz,FieldConstants.STATUS, SysConstants.FLAG_DISABLE);
                    }else {
                        ReflectUtil.setFieldValue(clazz,FieldConstants.STATUS, SysConstants.FLAG_SUCCESS);
                    }
                    this.mapper.update(t);
                }
            }
        }
    }


    /**
     *
     * @param fields 查询原id list 所需要的参数，例如 tenantId + userId 复合型 用户有的查询 menuId
     * @param rList 前端最终确定的id list
     * @param relaIdName 关联表关联Id
     * @param relationMapper 关系表操作mapper
     */
    protected <R extends BaseEntity,RM extends MBaseMapper<R>> void setRelationIds(Map<String,Object> fields, Collection<Object> rList, String relaIdName, RM relationMapper, Class<R> rClass){
        if(Objects.isNull(relaIdName)){
            throw DataException.entityRelaNull("关联id字段名为空");
        }
        if(Objects.isNull(fields)||fields.isEmpty()){
            throw DataException.entityRelaNull("关联Id查询条件为空");
        }

        R clazz = ReflectUtil.newInstance(rClass);
        for(String fieldName : fields.keySet()){
            clazz.where.equal(fieldName,fields.get(fieldName));
        }
        List<R> haveList = relationMapper.selectList(clazz);
        List<Object> oldList = new ArrayList<>();
        for(R r : haveList){
            Object val = ReflectUtil.getFieldValue(r,relaIdName);
            oldList.add(val);
        }
        Map<String, Collection<Object>> relationCollection = DataUtil.relationMap(oldList,rList);
        Collection<Object> addList = relationCollection.get("add");
        Collection<Object> removeLst = relationCollection.get("remove");

        if(!removeLst.isEmpty()){
            clazz.where.in(relaIdName,removeLst);
            relationMapper.del(clazz);
        }

        if(!addList.isEmpty()){
            List<R> addLst = new ArrayList<>();
            for(Object obj : addList){
                R newClazz = ReflectUtil.newInstance(rClass);
                for(String fieldName : fields.keySet()){
                    ReflectUtil.setFieldValue(newClazz,fieldName,fields.get(fieldName));
                }
                ReflectUtil.setFieldValue(newClazz,relaIdName,obj);
                addLst.add(newClazz);
            }
            relationMapper.insertBath(addLst);
        }
    }



    public List<T> getListPlus(T entity){
        QueryWrapper<T> queryWrapper = getQueryWrapper(entity);
        // 加上sql过滤
        queryWrapper.apply(StringUtils.isNotBlank(entity.getSqlFilter()),entity.getSqlFilter());
        return mapper.selectListPlus(queryWrapper);
    }

    /** 构建通用查询条件 */
    private QueryWrapper<T> getQueryWrapper(T entity) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        // 无查询条件时，将对象放入查询对象中，方便快速查询
        if(entity.getQueryWrapper().isEmptyOfWhere()){
            queryWrapper.setEntity(entity);
        } else {
            queryWrapper = (QueryWrapper<T>) entity.getQueryWrapper();
        }
        return queryWrapper;
    }

}
